﻿
#include <stdlib.h>
#include <memory.h>

#define LP_CORE

#include "lp_thread.h"
#include "lp_timer.h"
#include "lp_service.h"
#include "lp_socket.h"

static struct {
    int exit;
    LPConfig config;
    LPCond cond;
    uint32_t wait;
    uint32_t count;
    LPThread threads[256];
    LPThread timerThread;
}gCtx = { 0 };

static void
initWorkerContext (LPConfig* config){
    gCtx.config = *config;
    gCtx.count = config->workerCount;
    gCtx.wait = 0;
    lpInitCond(&gCtx.cond);
}

static void
freeWorkerContext (){
    free(gCtx.threads);
}

static void
wakupWorker(){
    if(!lpTryLockCond(&gCtx.cond)){ return; }
    if(gCtx.wait >= gCtx.count){
        lpSignalCond(&gCtx.cond);
    }
    lpUnlockCond(&gCtx.cond);
}

static void *
timerThread (void * arg){
    LPConfig config = gCtx.config;
    while (!gCtx.exit) {
        lpDispatchTimer();
        lpSleepms(config.timerSleep);
        wakupWorker();
    }
    return NULL;
}

static void *
workerThread (void * arg){
    while (!gCtx.exit) {
        if(lpDispatchWorker() || lpDispatchWorker()){
            wakupWorker();
        }else{
            lpLockCond(&gCtx.cond);
            gCtx.wait ++;
            lpWaitCond(&gCtx.cond);
            gCtx.wait--;
            lpUnlockCond(&gCtx.cond);
        }
    }
    return NULL;
}


LP_API void
lpDefault (LPConfig * conf){
    conf->workerCount = 2;
    conf->timerSleep = 16;
}

LP_API int
lpInit (LPConfig * config){
    gCtx.exit = 0;
    gCtx.config = *config;
    initWorkerContext(config);
    lpInitTimerContext();
    lpInitServiceContext();
    lpInitSocketContext();
    return 0;
}


LP_API int
lpStart (){
    LPConfig* config = &gCtx.config;
    uint32_t workerCount = gCtx.config.workerCount;
    lpNewThread(&gCtx.timerThread,
                timerThread, NULL, 1);
    for(uint32_t i = 0; i < workerCount; i ++){
        lpNewThread(&gCtx.threads[i],
                workerThread, NULL, 1);
    }
    return 0;
}

LP_API int
lpExit (){
    freeWorkerContext();
    lpExitTimeContext();
    lpExitServiceContext();
    lpExitSocketContext();
    return 0;
}
